// Copyright (c) 2010 Manuel Peinado Gallego <manuel.peinado@gmail.com>
// Distributed under the MIT license

// CMainView.h : interface of the CMainView class
//

#pragma once

#include "Node.h"
#include "Color.h"
#include "NodeManager.h"
#include "SelectionManager.h"
#include "Draggable.h"
#include "GizmoManager.h"
#include "View3d.h"



class CMainView 
    : public CView, 
      public View3d
{
public:

protected: // create from serialization only

    CMainView();


    // ************************************************************************
    // World/UIView overrides

    void onWorldChanged(World* newWorld);
    void onUiChanged(Ui* newUi);


    // ************************************************************************
    // View3d overrides

    gx::Vec3 unprojectImpl(const ScreenPoint & p, double z) const;
    ScreenPoint projectImpl(const gx::Vec3 & v) const;
    gx::Mat4 getCameraMatrixImpl() const;
    void getDimsImpl(int & w, int & h) const;
    void invalidateImpl();

    // ************************************************************************

    // ************************************************************************
    // OGL stuff
    
    HGLRC m_hRC;
    void MakeCurrent(void);

    void drawGrid() const;

    void draw();
    void resize(int w, int h);
    void initGL();

    // ************************************************************************

protected:

    // ************************************************************************
    // Implementation of SelectionListener
    
    void onSelectionChanged(SelectionManager * sender) override; 
    
    // ************************************************************************
    // Implementation of NodeListener
    
    void onNodeEvent(const NodeEvent&) override;

    // ************************************************************************
    // Implementation of Shader and material Listener
    
    //void onNodeAdded(NodeManager* sender, Node* node) override;
    //void onNodeRemoved(NodeManager* sender, Node* node) override;
    // ************************************************************************

    // ************************************************************************
    // A few helpers for implementing the texture transform message
    // handlers
    bool nodeHasTextureTransform(size_t layer);
    void addNodeTextureTransform(size_t layer);
    void removeNodeTextureTransform(size_t layer);
    void selectNodeTextureTransform(size_t layer);

    void onTexLayerEnvMode(EnvironmentMode envMode);
    void onUpdateTexLayerEnvMode(CCmdUI *pCmdUI, EnvironmentMode envMode);

    void onTexLayerRgbCombiMode(RgbCombinationMode mode);
    void onUpdateTexLayerRgbCombiMode(CCmdUI *pCmdUI, RgbCombinationMode mode);

    
    // ************************************************************************
    // Dragging stuff

    bool m_leftBtnDown;
    GizmoManager m_gizmoManager;

    // ************************************************************************
    // Single click detection
    
    //bool m_dragging;
    //ref<Node> m_draggedBlock;

    Draggable* m_draggable;

    UINT m_flags;
    CPoint m_point;

    // Timer related stuff. At the moment we only use timers
    // for single click / double click differentiation. 

    BEGIN_ENUM(ClickCycleState)
        IDLE, DOWN_RCVD, DRAGGING, FIRST_UP_RCVD, 
        DBL_CLCK_RCVD, SECOND_UP_RCVD
    END_ENUM(ClickCycleState)

    ClickCycleState m_leftBtnClickState;
    ClickCycleState m_rightBtnClickState;

    bool m_singleClickPossible;

    BEGIN_ENUM(TimerID)
        LBTN_DBL_CLK=1, RBTN_DBL_CLK
    END_ENUM(TimerID)

    // These are not real message handlers. We are forced to add this additional 
    // abstraction layer because MFC doesn't have proper single click detection
    // TODO move this into the OpenGLCtrl base class
    // Important: all the base classes must have the DBL_CLCKS window style set
    // or else double click messages won't reach this window, and our single 
    // click detection scheme will not work
    // TODO use the singleclick methods in actual code, right now they are not
    // used (we do all the handling inside the real message handlers)
    void onLSingleClick(UINT nFlags, CPoint point);
    void onRSingleClick(UINT nFlags, CPoint point);

    void onMButtonDrag(UINT iniFlags, CPoint iniPoint, 
        UINT currFlags, CPoint currPoint);
    void onLButtonDrag(UINT iniFlags, CPoint iniPoint, 
        UINT currFlags, CPoint currPoint);
    
    void onLDoubleClick(UINT nFlags, CPoint point);
    void onRDoubleClick(UINT nFlags, CPoint point);

    // ************************************************************************

    // ************************************************************************
    // Additional UI stuff

    void onBlockLDoubleClick(
            Node* clickedBlock, 
            UINT nFlags, CPoint point);
    void onBlockRDoubleClick(
            const Node & clickedBlock, int clickedFace, 
            UINT nFlags, CPoint point);

protected:

    // ************************************************************************

    DECLARE_DYNCREATE(CMainView)

// Attributes

public:
    // CWorldBuilderDoc* GetDocument() const;

// Operations
public:

// Overrides
public:
    virtual void OnDraw(CDC* pDC) override;  // overridden to draw this view
    virtual BOOL PreCreateWindow(CREATESTRUCT& cs) override;
protected:

// Implementation
public:
    virtual ~CMainView();
#ifdef _DEBUG
    virtual void AssertValid() const;
    virtual void Dump(CDumpContext& dc) const;
#endif

protected:

    void updatePivotCombo();
    void updateFrameCombo();

    void onManipId(GizmoAxesType id);
    void onUpdateManipId(CCmdUI *pCmdUI, GizmoAxesType id);

// Generated message map functions
protected:
    afx_msg void OnFilePrintPreview();
    afx_msg void OnContextMenu(CWnd* pWnd, CPoint point);
    DECLARE_MESSAGE_MAP()
    afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
    afx_msg void OnSize(UINT nType, int cx, int cy);
    afx_msg void OnClose();
    afx_msg BOOL OnEraseBkgnd(CDC* pDC);
    afx_msg void OnLButtonUp(UINT nFlags, CPoint point);
    afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
    afx_msg void OnMButtonUp(UINT nFlags, CPoint point);
    afx_msg void OnMButtonDown(UINT nFlags, CPoint point);
    afx_msg void OnRButtonUp(UINT nFlags, CPoint point);
    afx_msg void OnRButtonDown(UINT nFlags, CPoint point);
    afx_msg void OnMouseMove(UINT nFlags, CPoint point);
    afx_msg void OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags);
    afx_msg void OnKeyUp(UINT nChar, UINT nRepCnt, UINT nFlags);
    afx_msg BOOL OnMouseWheel(UINT nFlags, short zDelta, CPoint pt);
    afx_msg void OnTimer(UINT_PTR nIDEvent);
    afx_msg void OnLButtonDblClk(UINT nFlags, CPoint point);
    afx_msg void OnRButtonDblClk(UINT nFlags, CPoint point);
    afx_msg void OnChar(UINT nChar, UINT nRepCnt, UINT nFlags);
    afx_msg void OnEditCopy();
    afx_msg void OnUpdateEditCopy(CCmdUI *pCmdUI);
    afx_msg void OnEditPaste();
    afx_msg void OnUpdateEditPaste(CCmdUI *pCmdUI);
    afx_msg void OnEditUndo();
    afx_msg void OnEditRedo();
    afx_msg void OnUpdateEditUndo(CCmdUI *pCmdUI);
    afx_msg void OnUpdateEditRedo(CCmdUI *pCmdUI);
    afx_msg void OnEditCut();
    afx_msg void OnUpdateEditCut(CCmdUI *pCmdUI);
    afx_msg void OnManipCam();
    afx_msg void OnUpdateManipCam(CCmdUI *pCmdUI);
    afx_msg void OnManipObj();
    afx_msg void OnUpdateManipObj(CCmdUI *pCmdUI);
    afx_msg void OnManipTransl();
    afx_msg void OnUpdateManipTransl(CCmdUI *pCmdUI);
    afx_msg void OnManipRot();
    afx_msg void OnUpdateManipRot(CCmdUI *pCmdUI);
    afx_msg void OnManipScale();
    afx_msg void OnUpdateManipScale(CCmdUI *pCmdUI);
    afx_msg void OnManipPivot();
    afx_msg void OnUpdateManipPivot(CCmdUI *pCmdUI);
    afx_msg void OnManipFrame();
    afx_msg void OnUpdateManipFrame(CCmdUI *pCmdUI);
    afx_msg void OnManipComboCloseup();
    afx_msg void OnViewPerspective();
    afx_msg void OnUpdateViewPerspective(CCmdUI *pCmdUI);
    afx_msg void OnViewClear();
    afx_msg LRESULT OnUpdateGizmoCombos(WPARAM, LPARAM);
    afx_msg void OnNewEmptyShader();
    afx_msg void OnNewVertexShader();
    afx_msg void OnNewFragmentShader();
    afx_msg void OnLoadVertexShader();
    afx_msg void OnLoadFragmentShader();
    afx_msg void OnPrintUniformVariables();
    afx_msg void OnAddTexture();
    afx_msg void OnAddTextureLayerAfter();
    afx_msg void OnNodeDelete();
    afx_msg void OnNodeAddTextureTransform0();
    afx_msg void OnUpdateNodeAddTextureTransform0(CCmdUI* pCmdUI);
    afx_msg void OnNodeAddTextureTransform1();
    afx_msg void OnUpdateNodeAddTextureTransform1(CCmdUI* pCmdUI);
    afx_msg void OnNodeAddTextureTransform2();
    afx_msg void OnUpdateNodeAddTextureTransform2(CCmdUI* pCmdUI);
    afx_msg void OnNodeAddTextureTransform3();
    afx_msg void OnUpdateNodeAddTextureTransform3(CCmdUI* pCmdUI);
    afx_msg void OnNodeRemoveTextureTransform0();
    afx_msg void OnUpdateNodeRemoveTextureTransform0(CCmdUI* pCmdUI);
    afx_msg void OnNodeRemoveTextureTransform1();
    afx_msg void OnUpdateNodeRemoveTextureTransform1(CCmdUI* pCmdUI);
    afx_msg void OnNodeRemoveTextureTransform2();
    afx_msg void OnUpdateNodeRemoveTextureTransform2(CCmdUI* pCmdUI);
    afx_msg void OnNodeRemoveTextureTransform3();
    afx_msg void OnUpdateNodeRemoveTextureTransform3(CCmdUI* pCmdUI);
    afx_msg void OnNodeSelectTextureTransform0();
    afx_msg void OnUpdateNodeSelectTextureTransform0(CCmdUI* pCmdUI);
    afx_msg void OnNodeSelectTextureTransform1();
    afx_msg void OnUpdateNodeSelectTextureTransform1(CCmdUI* pCmdUI);
    afx_msg void OnNodeSelectTextureTransform2();
    afx_msg void OnUpdateNodeSelectTextureTransform2(CCmdUI* pCmdUI);
    afx_msg void OnNodeSelectTextureTransform3();
    afx_msg void OnUpdateNodeSelectTextureTransform3(CCmdUI* pCmdUI);
};

#ifndef _DEBUG  // debug version in WorldBuilderView.cpp
inline CWorldBuilderDoc* CMainView::GetDocument() const
   { return reinterpret_cast<CWorldBuilderDoc*>(m_pDocument); }
#endif

